#include "extractGraph.h"


ExtractGraph::ExtractGraph()
{

}

//提取输入原始图片的蓝色层
Mat ExtractGraph::extractBlueLayer(Mat src)
{
    Mat blueImg;
    vector<Mat> BGRImg(3);
    //分割出元件的blue通道
    split(src, BGRImg);
    blueImg = BGRImg[0]-BGRImg[1];
    return blueImg;
}
//提取图片的所有元器件
Mat ExtractGraph::extractComponet(Mat src, double thresh, double maxValue)
{
    Mat blueImg = src.channels() == 1 ? src : extractBlueLayer(src);
    Mat binnaryImg;
    //阈值化提取出想要的图像
    threshold(blueImg, binnaryImg, thresh, maxValue, THRESH_BINARY);
    morphologyEx(binnaryImg, binnaryImg, MORPH_CLOSE, Mat());
    return binnaryImg;
}
//提取图片中的文字
Mat ExtractGraph::extractText(Mat src, double thresh, double threshBright, double maxValue)
{
    Mat blueImg = extractBlueLayer(src);
    Mat binnaryText, binnaryTextErode, binnaryTextDilate;
    //阈值化提取出想要的图像
    threshold(blueImg, binnaryText, thresh, maxValue, THRESH_TOZERO_INV);
    threshold(binnaryText, binnaryText, threshBright, maxValue, THRESH_BINARY);    //加深颜色
    //文字图像处理先膨胀后腐蚀再膨胀
    dilate(binnaryText, binnaryTextDilate, Mat(), Point(-1, -1), 1);
    erode(binnaryTextDilate, binnaryTextErode, Mat(), Point(-1, -1), 2);
    dilate(binnaryTextErode, binnaryTextDilate, Mat(), Point(-1, -1), 1);

    binnaryText = binnaryTextDilate;

    return binnaryText;
}
//提取图片的初始线路
Mat ExtractGraph::extractLocal(Mat src, double thresh, double maxValue)
{
    vector<Mat> srcLayer;
    split(src, srcLayer);

    //阈值检出
    Mat srcLocate;
    threshold(srcLayer[0], srcLocate, thresh, maxValue, THRESH_BINARY_INV);
    //对图形进行开操作
    dilate(srcLocate, srcLocate, Mat(), Point(-1, -1), 1);
    erode(srcLocate, srcLocate, Mat(), Point(-1, -1), 3);

    return srcLocate;
}
//提取图片中的电子器件,并组合成图片返回
Mat ExtractGraph::extractDev(Mat src, vector<Mat>& imgVector)
{
    //获取电子器件的轮廓
    vector<vector<Point>> contours;
    findContours(src, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//    Mat showImg = src.clone().setTo(0);
//    drawContours(showImg, contours, -1, Scalar(255));
//    imshow("srcComponentShowImg", showImg);
//    cout << "电子元件轮廓数量:" << contours.size() << endl;
    int rectNum = contours.size();

    //检测元器件矩形轮廓
    vector<Rect> rectVector(rectNum);
    for (int i=0; i<rectNum; i++)
    {
        rectVector[i] = boundingRect(contours[i]);
        rectVector[i] += Size(10,10);
        rectVector[i] += Point(-5,-5);
    }
//    cout << "检测到的电子器件矩形数量:" << rectVector.size() << endl;

    //画出检测到的器件矩形轮廓
    Mat rectanglesImg = src.clone().setTo(0);
    for (int i=0; i<rectNum; i++)
    {
        rectangle(rectanglesImg, rectVector[i], Scalar(255));
    }
//    imshow("rectangleImg", rectanglesImg);

    //根据矩形轮廓分割出器件图形
    imgVector.clear();
    imgVector.resize(rectNum);
    Mat devImgShow;
    for (int i=0; i<rectNum; i++)
    {
        imgVector[i] = Mat(src, rectVector[i]);
    }
    multipleImage(imgVector, devImgShow, 4, NO_CHANGE);
//    imshow("devImgShow", devImgShow);

    return devImgShow;
}
//提取图片中的器件,并组成图片返回
Mat ExtractGraph::extractDev(Mat src, vector<Rect>& rectVector)
{
    //获取电子器件的轮廓
    vector<vector<Point>> contours;
    findContours(src, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    int rectNum = contours.size();

    //检测元器件矩形轮廓
    rectVector.clear();
    rectVector.resize(rectNum);
    for (int i=0; i<rectNum; i++)
    {
        rectVector[i] = boundingRect(contours[i]);
        rectVector[i] += Size(10,10);
        rectVector[i] += Point(-5,-5);
    }
     //画出检测到的器件矩形轮廓
    Mat rectImg = src.clone().setTo(0);
    for (int i=0; i<rectNum; i++)
        rectangle(rectImg, rectVector[i], Scalar(255));

    return rectImg;
}
//提取图片中的线路
void ExtractGraph::extractCircultPoints(Mat src, vector<vector<Point>> &circultVector)
{
    //通过检测矩形轮廓绘制直线
    vector<vector<Point>> contours;
    findContours(src.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    Mat showImg = src.clone().setTo(0);
    drawContours(showImg, contours, -1, Scalar(255));
    imshow("srcContoursShowImg", showImg);
    cout << "轮廓数量:" << contours.size() << endl;
    int rectNum = contours.size();

    //检测线路矩形轮廓
    vector<Rect> rectVector(rectNum);
    for (int i=0; i<rectNum; i++)
        rectVector[i] = boundingRect(contours[i]);
    cout << "检测到的矩形数量:" << rectVector.size() << endl;

    //通过矩形轮廓融合直线
    circultVector.resize(rectNum);
    for (int i=0; i<rectNum; i++)
        circultVector[i].resize(2); //重定义大小
    for (int i=0; i<rectNum; i++)
    {
        if (rectVector[i].width > rectVector[i].height)
        {
            //横线
            circultVector[i][0] =
                    Point(rectVector[i].x, rectVector[i].y + rectVector[i].height/2);
            circultVector[i][1] =
                    Point(rectVector[i].x + rectVector[i].width, rectVector[i].y + rectVector[i].height/2);
        }
        else
        {
            //竖线
            circultVector[i][0] =
                    Point(rectVector[i].x + rectVector[i].width/2, rectVector[i].y);
            circultVector[i][1] =
                    Point(rectVector[i].x + rectVector[i].width/2, rectVector[i].y + rectVector[i].height);
        }
    }
    //描绘出直线
    Mat linesImg = src.clone().setTo(0);
    for (int i=0; i<rectNum; i++)
        line(linesImg, circultVector[i][0], circultVector[i][1], Scalar(255));
    imshow("srcLinesImg", linesImg);
}
//提取图片中的线路
Mat ExtractGraph::extractCircultPoints(Mat src)
{
    //通过检测矩形轮廓绘制直线
    vector<vector<Point>> contours;
    findContours(src.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//    Mat showImg = src.clone().setTo(0);
//    drawContours(showImg, contours, -1, Scalar(255));
//    imshow("srcContoursShowImg", showImg);
//    cout << "轮廓数量:" << contours.size() << endl;
    int rectNum = contours.size();

    //检测线路矩形轮廓
    vector<Rect> rectVector(rectNum);
    for (int i=0; i<rectNum; i++)
        rectVector[i] = boundingRect(contours[i]);
//    cout << "检测到的矩形数量:" << rectVector.size() << endl;

    //通过矩形轮廓融合直线
    vector<vector<Point>> circultVector(rectNum, vector<Point>(2));
    for (int i=0; i<rectNum; i++)
    {
        if (rectVector[i].width > rectVector[i].height)
        {
            //横线
            circultVector[i][0] =
                    Point(rectVector[i].x, rectVector[i].y + rectVector[i].height/2);
            circultVector[i][1] =
                    Point(rectVector[i].x + rectVector[i].width, rectVector[i].y + rectVector[i].height/2);
        }
        else
        {
            //竖线
            circultVector[i][0] =
                    Point(rectVector[i].x + rectVector[i].width/2, rectVector[i].y);
            circultVector[i][1] =
                    Point(rectVector[i].x + rectVector[i].width/2, rectVector[i].y + rectVector[i].height);
        }
    }
    //描绘出直线
    Mat linesImg = src.clone().setTo(0);
    for (int i=0; i<rectNum; i++)
        line(linesImg, circultVector[i][0], circultVector[i][1], Scalar(255));

    return linesImg;
}

void ExtractGraph::getProcessImg(Mat src)
{
    processImg.push_back(extractComponet(src));
    processImg.push_back(extractText(src));
}


//提取图片的角点特征
Mat ExtractGraph::extractKeyPoints(const vector<Mat>& devImgVector,
                                   vector<vector<KeyPoint>>& devKeyPointsVector,
                                   int imgCols,
                                   int mode)
{
    int devNum = devImgVector.size();
    //对提取出的元器件进行SIFT特征提取
    Ptr<SIFT> detector = SIFT::create();
    devKeyPointsVector.clear(); devKeyPointsVector.resize(devNum);  //对输入进行清除
    //提取
    detector->detect(devImgVector, devKeyPointsVector);
    //绘制各图片的关键点图
    vector<Mat> devKeyPointsImgVector(devNum);
    for (int i=0; i<devNum; i++)
    {
        drawKeypoints(devImgVector[i], devKeyPointsVector[i], devKeyPointsImgVector[i],
                      Scalar::all(-1));
    }
    //绘制模板图的KeyPoints图片
    Mat devKeyPointsImgShow;
    multipleImage(devKeyPointsImgVector, devKeyPointsImgShow, imgCols, mode);

    return devKeyPointsImgShow;
}
//提取图片的角点特征
Mat ExtractGraph::extractKeyPoints(const Mat &templateImg,
                                   vector<KeyPoint> &templateKeyPoints)
{
    templateKeyPoints.clear();
    Ptr<SIFT> detector = SIFT::create();
    detector->detect(templateImg, templateKeyPoints);

    Mat templateKeyPointsImg;
    drawKeypoints(templateImg, templateKeyPoints, templateKeyPointsImg, Scalar::all(-1));

    return templateKeyPointsImg;
}

//提取特征点描述
void ExtractGraph::extractDescriptor( vector<Mat> &devImgVector,
                                    vector<vector<KeyPoint>> &devKeyPointsVector,
                                    vector<Mat> &devDescriptorVector)
{
    int devNum = devImgVector.size();

    Ptr<SIFT> detector = SIFT::create();
    devDescriptorVector.clear(); devDescriptorVector.resize(devNum);
    detector->compute(devImgVector, devKeyPointsVector, devDescriptorVector);
}
//提取特征点描述
void ExtractGraph::extractDescriptor( Mat &templateImg,
                                     vector<KeyPoint> &templateKeyPoints,
                                     Mat &templateDescriptor)
{
    Ptr<SIFT> detector = SIFT::create();

    templateKeyPoints.clear();
    detector->compute(templateImg, templateKeyPoints, templateDescriptor);
}
